using System;
using System.Globalization;


namespace Waymex.Gps.Nmea
{
	/// <summary>
	/// GGA NMEA sentence class.
	/// </summary>
	public class SentenceGga : Sentence
	{

		private const string C_SENTENCE_TYPE = "GGA";

        private System.DateTime m_dtUTC = Convert.ToDateTime("01 Jan 0001", CultureInfo.InvariantCulture);
		private double m_dblLatitude = 0.0;
		private double m_dblLongitude = 0.0;
		private GgaQuality m_utGPSQuality;
		private int m_intSatellitesInView = 0;
		private double m_dblHorizontalDilution = 0.0;
		private double m_dblAntennaAltitude = 0.0;
		private double m_dblGeoidalHeight = 0.0;
		private long m_lngDGPSDataAge = 0;
		private long m_lngDRStationID = 0;
		
		/// <summary>
		/// Enumeration used to describe the GGA quality options.
		/// </summary>
		public enum GgaQuality
		{
			/// <summary>
			/// Unknown
			/// </summary>
			Unknown = 0,
			/// <summary>
			/// No fix.
			/// </summary>
			NoFix = 1,
			/// <summary>
			/// Not a DGPS fix.
			/// </summary>
			NonDgpsFix = 2,
			/// <summary>
			/// DGPS fix.
			/// </summary>
			DgpsFix = 3,
			/// <summary>
			/// Estimated.
			/// </summary>
			Estimated = 4
		}

		/// <summary>
		/// Constructor for the SentenceGga class.
		/// </summary>
        public SentenceGga(string sentence)
            : base(sentence)
		{
			try
			{
				//check the type to ensure that we can continue
                if (this.TypeId.ToUpper(CultureInfo.InvariantCulture) == C_SENTENCE_TYPE)
				{
                    Populate(sentence);
				}
				else
				{
					throw new InvalidSentence(C_MSG_001);
				}
			}
			catch(Exception e)
			{
                throw new InvalidSentence(e.Message, e);
			}
		}
		private void Populate(string p_strSentence)
		{
			int intTemp = 0;

			//add sentence specifics here
            if(SentenceItemExists(1)) m_dtUTC = Convert.ToDateTime(FormatTime(m_astrSentence[1]), CultureInfo.InvariantCulture);
			if(SentenceItemExists(3)) m_dblLatitude = FormatPosition(m_astrSentence[2] + m_astrSentence[3]);
			if(SentenceItemExists(5)) m_dblLongitude = FormatPosition(m_astrSentence[4] + m_astrSentence[5]);

			if(SentenceItemExists(6)) 
			{
				if(IsNumeric(m_astrSentence[6]))
				{
                    intTemp = Convert.ToInt32(m_astrSentence[6], CultureInfo.InvariantCulture);
				}

				switch(intTemp)
				{
					case 0:
						m_utGPSQuality = GgaQuality.NoFix;
						break;
					case 1:
						m_utGPSQuality = GgaQuality.NonDgpsFix;
						break;
					case 2:
						m_utGPSQuality = GgaQuality.DgpsFix;
						break;
					case 6:
						m_utGPSQuality = GgaQuality.Estimated;
						break;
					default:
						m_utGPSQuality = GgaQuality.Unknown;
						break;
				}
			}
			else
			{
				m_utGPSQuality = GgaQuality.Unknown;
			}
		
			if(IsNumeric(m_astrSentence[7]))
                m_intSatellitesInView = Convert.ToInt32((m_astrSentence[7]), CultureInfo.InvariantCulture);
			
			m_dblHorizontalDilution = FormatNumber(m_astrSentence[8]);
			m_dblAntennaAltitude = FormatNumber(m_astrSentence[9]);
            //10 is units antenna height
			m_dblGeoidalHeight = FormatNumber(m_astrSentence[11]);
			//12 units of geoidal separation
			if(IsNumeric(m_astrSentence[13]))
                m_lngDGPSDataAge = Convert.ToInt64(m_astrSentence[13], CultureInfo.InvariantCulture);

			if(IsNumeric(m_astrSentence[14]))
                m_lngDRStationID = Convert.ToInt64(m_astrSentence[14], CultureInfo.InvariantCulture);
		}

		///<summary>
		///Returns the the time (UTC).
		///</summary>
		public System.DateTime Utc
		{
			get
			{
				return m_dtUTC;
			}
			set
			{
				m_dtUTC = value;
			}
		}

		///<summary>
		///Returns the Latitude in Degrees. Negative values indicate positions West.
		///</summary>
		public double Latitude
		{
			get
			{
				return m_dblLatitude;
			}
			set
			{
				m_dblLatitude = value;
			}
		}

		///<summary>
		///Returns the Longitude in Degrees. Negative values indicate positions South.
		///</summary>
		public double Longitude
		{
			get
			{
				return m_dblLongitude;
			}
			set
			{
				m_dblLongitude = value;
			}
		}

		///<summary>
		///Returns the quality of the fix data.
		///</summary>
		public GgaQuality GpsQuality
		{
			get
			{
				return m_utGPSQuality;
			}
			set
			{
				m_utGPSQuality = value;
			}
		}

		///<summary>
		///Returns the number of satellites in view.
		///</summary>
		public int SatellitesInView
		{
			get
			{
				return m_intSatellitesInView;
			}
			set
			{
				m_intSatellitesInView = value;
			}
		}

		///<summary>
		///Returns the Horizontal Dilution of Precision.
		///</summary>
		public double HorizontalDilution
		{
			get
			{
				return m_dblHorizontalDilution;
			}
			set
			{
				m_dblHorizontalDilution = value;
			}
		}

		///<summary>
		///Returns the Antenna Altitude above/below mean-sea-level (Geoid) in meters.
		///</summary>
		public double AntennaAltitude
		{
			get
			{
				return m_dblAntennaAltitude;
			}
			set
			{
				m_dblAntennaAltitude = value;
			}
		}

		///<summary>
		///Returns the difference between the WGS-84 Earth ellipsoid and mean-sea-level (Geoid),
		///a negative value indicates that the Geoid is below the ellipsoid.
		///</summary>
		public double GeoidalHeight
		{
			get
			{
				return m_dblGeoidalHeight;
			}
			set
			{
				m_dblGeoidalHeight = value;
			}
		}

		///<summary>
		///Returns the age of differential GPS data. Time in seconds since last SC104 type 1 or update.
		///This property will be 0 when DGPS is not used.
		///</summary>
		public long DgpsDataAge
		{
			get
			{
				return m_lngDGPSDataAge;
			}
			set
			{
				m_lngDGPSDataAge = value;
			}
		}

		///<summary>
		///Returns the Differential Reference Station ID.
		///</summary>
		public long DRStationId
		{
			get
			{
				return m_lngDRStationID;
			}
			set
			{
				m_lngDRStationID = value;
			}
		}
	}
}
